﻿using mozhi.smarterp.Finance.Accounts;
using mozhi.smarterp.Finance.Accounts.Repository;
using mozhi.smarterp.Finance.Enums;
using mozhi.smarterp.Finance.Querys;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Mozhi.Abp.Core.Extensions;
using mozhi.smarterp.Finance.Finances.Repository;
using System;

namespace mozhi.smarterp.Finance.Finances.Services.EndPeriodProcess
{
    /// <summary>
    /// 计提所得税
    /// </summary>
    public class AccrualIncomeTaxEndPeriodProcessor : EndPeriodProcessorBase<AccountBalance>
    {
        private List<AccountBalance> _initalizeBalances;

        public AccrualIncomeTaxEndPeriodProcessor(EndPeriodProcessItem item, int period,
            IServiceProvider serviceProvider) : base(item, period, serviceProvider)
        {
        }

        protected override async Task LoadCalculationDataAsync()
        { 
            var accountBalanceRepository = _serviceProvider.GetService(typeof(IAccountBalanceRepository)) as IAccountBalanceRepository;

            _initalizeBalances = await accountBalanceRepository.FindAsync(new AccountBalanceQuery() { Period = (await _organizationRepository.GetAsync()).ActivatedDate.Value.ToPeriod().ToPrePeriod(), IncludeCurrency = false, IncludeDimension = false });

            await base.LoadCalculationDataAsync();
        }


        protected override async Task LoadAccountAsync()
        {
            var accountRepository = _serviceProvider.GetService(typeof(IAccountRepository)) as IAccountRepository;

            _accounts = await accountRepository.GetListAsync();
        }


        protected override async Task<EndPeriodProcessResult> HandleDataAsync()
        {
            EndPeriodProcessResult result = null;

            ///本年利润科目
            var account4103 = GetAccount(GetEndPeriodProcessSettingAsync("4103")?.CustomAccountCode);

            if (account4103 == null)
                return result;

            var account222106 = GetAccount(GetEndPeriodProcessSettingAsync("2221.06")?.CustomAccountCode);

            if (account222106 == null)
                return result;

            //取所有的损益类科目
            //收益类科目
            var revenueAccounts = _accounts.Where(x => x.AccountType == AccountType.OperatingRevenue || x.AccountType == AccountType.OtherRevenue).Where(x => x.IsLeaf).ToList();

            //费用类科目
            var expenseAccounts = _accounts.Where(x => x.AccountType == AccountType.OperatingCostsAndTaxes || x.AccountType == AccountType.OtherLosses
            || x.AccountType == AccountType.PeriodCharge || x.AccountType == AccountType.IncomeTax).Where(x => x.IsLeaf).ToList();


            //1. 获取本年到现在的收益
            var revenueAccountIds = revenueAccounts.Select(x => x.Id).ToList();


            var incomeAmount = _data.Where(x => revenueAccountIds.Contains(x.AccountId)).Sum(x => x.CreditAmount.ToDecimal() - x.DebitAmount.ToDecimal())
                + _initalizeBalances.Where(x => revenueAccountIds.Contains(x.AccountId)).Sum(x => x.CurrentYearCreditAmount.ToDecimal());

            //2. 获取本年费用金额
            var expenseAccountIds = expenseAccounts.Select(x => x.Id).ToList();

            var expenseAmount = _data.Where(x => expenseAccountIds.Contains(x.AccountId)).Sum(x => x.DebitAmount.ToDecimal() - x.CreditAmount.ToDecimal())
                + _initalizeBalances.Where(x => expenseAccountIds.Contains(x.AccountId)).Sum(x => x.CurrentYearDebitAmount.ToDecimal());


            //3. 获取本期结转损益凭证里面的贷方和借方的发生额
            var profitLossBalances = await GetProfitLossJournalBalanceAsync();

            if (profitLossBalances != null && profitLossBalances.Count > 0)
            {
                incomeAmount += profitLossBalances.Where(x => revenueAccountIds.Contains(x.AccountId)).Sum(x => x.DebitAmount.ToDecimal() - x.CreditAmount.ToDecimal());

                expenseAmount += profitLossBalances.Where(x => expenseAccountIds.Contains(x.AccountId)).Sum(x => x.CreditAmount.ToDecimal() - x.DebitAmount.ToDecimal());
            }

            //4. 最后的本年利润
            var profitAmount = incomeAmount - expenseAmount;


            //5. 所得税税率
            var taxRate = await GetIncomeTaxRateAsync();

            //6. 累计应计提所得税
            var incomeTaxAmount = profitAmount <= 0 ? 0 : taxRate * profitAmount / 100m;

            //7. 应交的所得税金额
            var payableIncomeTaxAmount = _data.Where(x => x.AccountId == account222106.Id).Sum(x => x.CreditAmount.ToDecimal())
                + _initalizeBalances.Where(x => x.AccountId == account222106.Id).Sum(x => x.CurrentYearCreditAmount.ToDecimal());

            //结转金额
            var transferAmount = incomeTaxAmount - payableIncomeTaxAmount;

            result = new EndPeriodProcessResult(Guid.NewGuid(), _item.Id, _period , EndPeriodProcessType.IncomeTax);

            result.Change(transferAmount > 0, false, null, transferAmount > 0 ? transferAmount : null ,false);

            var items = GetResultItems(result.Id, profitAmount, taxRate, payableIncomeTaxAmount);

            items.ForEach(item =>
            {
                result.AddItem(item);

            });

            return result;
        }

        /// <summary>
        /// 处理凭证创建逻辑
        /// </summary>
        /// <returns></returns>
        protected override async Task<Journal> HandleGenerateJournalAsync()
        {
            Journal joural = null;

            ///所得税费用
            var account6801 = GetAccount(GetEndPeriodProcessSettingAsync("6801")?.CustomAccountCode);

            if (account6801 == null)
                return joural;

            //应交所得税
            var account222106 = GetAccount(GetEndPeriodProcessSettingAsync("2221.06")?.CustomAccountCode);

            if (account222106 == null)
                return joural;


            //测算结果
            var measureResult = _processResult;

            var amount = measureResult.MeasureValue.Value;

            var journalMananger = _serviceProvider.GetService(typeof(JournalManager)) as JournalManager;

            var defaultJournalNumberPrefix = await GetJournalDefaultNumberPrefix();

            var journal = await journalMananger.Create(_guidGenerator.Create(), defaultJournalNumberPrefix.Id, _period.ToLastDayDateTime());

            var journalItemFor6801 = await GetJournalItemAsync("计提所得税", amount, account6801, null, 0, AccountDirectionType.Debit);

            var journalItemFor222106 = await GetJournalItemAsync("计提所得税", amount, account222106, null, 1, AccountDirectionType.Credit);

            var journalItems = new List<JournalItem>() { journalItemFor6801, journalItemFor222106 };

            await journalMananger.ChangeItems(journal, journalItems);

            return journal;
        }


        #region
        /// <summary>
        /// 获取结转比例
        /// </summary>
        /// <param name="incomeAmount">主营业务收入金额</param>
        /// <param name="incomeAmount">库存商品金额</param>
        /// <returns></returns>
        private async Task<decimal> GetIncomeTaxRateAsync()
        {
            decimal result = 25.000000M;

            var previousPeriod = _period.ToPrePeriod();

            var endPeriodProcessRepository = _serviceProvider.GetService(typeof(IEndPeriodProcessResultRepository)) as IEndPeriodProcessResultRepository;

            //查上一期的处理结果
            var previousProcessResults = await endPeriodProcessRepository.FindAsync(new EndPeriodProcessResultQuery() { ItemId = _item.Id, Period = previousPeriod });

            var previousProcessResult = previousProcessResults.FirstOrDefault();

            result = previousProcessResult == null ? result : previousProcessResult.Items.FirstOrDefault(x=>x.Index==2).Value.ToDecimal();

            result = result <= 0 ? 25.000000M : Math.Round(result, 6, MidpointRounding.AwayFromZero);

            return result;

        }


        /// <summary>
        /// 获取子级测算项
        /// </summary>
        /// <param name="incomeAmount"></param>
        /// <param name="taxRate"></param>
        /// <param name="payableIncomeTaxAmount"></param>
        /// <returns></returns>
        private List<EndPeriodProcessResultItem> GetResultItems(Guid resultId , decimal? profitAmount, decimal taxRate, decimal? payableIncomeTaxAmount)
        {
            var result = new List<EndPeriodProcessResultItem>
            {
                //设置子处理项
                new EndPeriodProcessResultItem(Guid.NewGuid(), resultId, "本年利润合计", profitAmount?.ToString(), 1, 1 ,false),
                new EndPeriodProcessResultItem(Guid.NewGuid(), resultId, "所得税率", taxRate.ToString(), 2, 2, false),
                new EndPeriodProcessResultItem(Guid.NewGuid(), resultId, "应交所得税合计", payableIncomeTaxAmount.ToString(), 1, 3, false)
            };

            return result;
        }

       

        #endregion
    }
}
